﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using FirebirdSql.Data.FirebirdClient;
using TimeSnapperPluginAPI;

namespace GCalPlugin
{
    public class GCalPlugin : ITimeSnapperPlugin
    {
        private GCalJournal journal;
        private IServices services;
        private string Username;
        private string Password;
        private string FeedUrl;
        private bool IsEnabled = true;

        public TimeSnapperEvent[] SubscribesTo()
        {
            //Let's subscribe to everything so we can log every event.
            TimeSnapperEvent[] subscribesTo = {
                                 //TimeSnapperEvent.Archived, 
                                 //TimeSnapperEvent.ArchivingCancel ,
                                 //TimeSnapperEvent.AutoPoppingUpCancel ,
                                 //TimeSnapperEvent.Closing,
                                 TimeSnapperEvent.ComputerIdle,
                                 TimeSnapperEvent.FlagSaved ,
                                 TimeSnapperEvent.FlagSavingCancel ,
                                 TimeSnapperEvent.PluginsLoaded ,
                                 //TimeSnapperEvent.SnapshotDeleted ,
                                 //TimeSnapperEvent.SnapshotDeletingCancel ,
                                 TimeSnapperEvent.SnapshotSaved ,
                                 //TimeSnapperEvent.SnapshotTakenSavingCancel  ,
                                 //TimeSnapperEvent.SnapshotTakingCancel
                                };
            return subscribesTo;
                                 
        }

        public TimeSnapperMenuItem[] MenuItems()
        {
            var itm = new CreateTaskMenuItem(TimeSnapperMenu.TimeBarContext, "Create Task + Break");
            itm.CreateTask += itm_CreateTask;
                
            return new TimeSnapperMenuItem[]
                       {
                           itm
                       };
        }

        void itm_CreateTask(object sender, CreateTaskEventArgs e)
        {
            var dataTable = services.DatabaseServices.ExecuteQuery(string.Format("select SNAPDATE,PROGRAM,PROGRAMCAPTION from activity where id={0}",e.start.ActivityId), "activity");
            if(dataTable.Rows.Count == 1)
            {
                var snapdate = dataTable.Rows[0][0];
                Debug.Print("Start of selection: {0}",snapdate);
            }
            dataTable = services.DatabaseServices.ExecuteQuery(string.Format("select SNAPDATE,PROGRAM,PROGRAMCAPTION from activity where id={0}", e.end.ActivityId), "activity");
            if (dataTable.Rows.Count == 1)
            {
                var snapdate = dataTable.Rows[0][0];
                Debug.Print("End of selection: {0}", snapdate);
            }
        }

        public object HandleEvent(TimeSnapperEvent timeSnapperEvent, IServices services, EventArgs args)
        {
            if (!IsEnabled) return null;

            Flag flag;
            
            switch (timeSnapperEvent)
            {
                case TimeSnapperEvent.PluginsLoaded:
                    this.services = services;//save ref
                    //load settings
                    LoadConfig();
                    break;
                case TimeSnapperEvent.ComputerIdle:
                    var specificArgs5 = (ComputerIdleEventArgs) args;
                    //specificArgs4.Duration;
                    break;
                case TimeSnapperEvent.FlagSavingCancel:
                    var specificArgs2 = (FlagSavingCancelEventArgs)args;
                    //specificArgs.Cancel = true; 
                    //^^^ this would cancel the saving of the flag
                    flag = specificArgs2.Flag;
                    //flag.Text6 = "testing123";//this will overwrite the data before the save but not autopopulate;
                    break;
                case TimeSnapperEvent.SnapshotSaved:
                    {
                        var specificArgs4 = (TimeSnapperPluginAPI.SnapshotSavedEventArgs)args;
                        var activity = specificArgs4.Activity;
                        //TODO: we could check past activities and launch the new Flag Popup if program has changed
                        //var dataTable = services.DatabaseServices.ExecuteQuery("select program,programcaption,sum(duration) from activity where snapdate between '1/18/2011' and '01/18/2011 23:59:59' group by program,programcaption", "activity");
                    }
                    break;
                case TimeSnapperEvent.SnapshotTakingCancel:
                    {
                        var specificArgs3 = (TimeSnapperPluginAPI.SnapshotTakingCancelEventArgs)args;
                        //specificArgs.Cancel = true; 
                        //^^^ this would cancel the taking of the snapshot
                    }
                    break;
                case TimeSnapperEvent.FlagSaved:
                    var specificArgs = (FlagSavedEventArgs)args;
                    flag = specificArgs.Flag;
                    Debug.WriteLine("Flag Saved Event");
                    ThreadPool.QueueUserWorkItem((o) => HandleFlagSaved(flag, services));
                    break;
            }
            return null;
        }

        private void LoadConfig()
        {
            IsEnabled = services.SettingsServices.GetPropertyValue(GCalConfigurationForm.gcal_PluginEnabled, "false") == "true";
            Username = services.SettingsServices.GetPropertyValue(GCalConfigurationForm.gcal_User, string.Empty);
            Password = services.SettingsServices.GetPropertyValue(GCalConfigurationForm.gcal_Pass, string.Empty);
            FeedUrl = services.SettingsServices.GetPropertyValue(GCalConfigurationForm.gcal_Feed, string.Empty);
        }

        private void HandleFlagSaved(Flag flag, IServices services)
        {
            //for now do not skip
            if (false && DateTime.Now.Subtract(flag.FlagDate).Minutes > 10)
            {
                Debug.WriteLine("Flag older than 10 minutes ago. Skipping.");
                return;
            }
            if (flag.FlagType == "BREAK" || flag.FlagType == "EOD" || flag.FlagType == "TASK")
            {
                //search for Task before that
                var dataTable = services.FlagServices.GetFlags(flag.FlagDate.AddDays(-1), flag.FlagDate.AddSeconds(-1));
                List<Flag> flags = new List<Flag>();
                foreach (DataRow row in dataTable.Rows)
                {
                    flags.Add(new Flag()
                                  {
                                      FlagId = (int)row["ID"],
                                      FlagDate = (DateTime)row["FLAGDATE"],
                                      FlagType = (string)row["FLAGTYPE"],
                                      Text1 = (string)row["TEXT1"],
                                      Text2 = (string)row["TEXT2"],
                                      Text3 = (string)row["TEXT3"],
                                      Text4 = (string)row["TEXT4"],
                                      Text5 = (string)row["TEXT5"],
                                      Text6 = (string)row["TEXT6"],
                                      Comment = (string)row["COMMENT"],
                                      Color = Color.FromArgb((int)row["COLOR"])
                                  });
                    //column ID value: 619138
                    //column FLAGDATE value: 01/18/2011 16:05:00
                    //column FLAGTYPE value: EOD
                    //column TEXT1 value: 
                    //column TEXT2 value: 
                    //column TEXT3 value: 
                    //column TEXT4 value: 
                    //column TEXT5 value: 
                    //column TEXT6 value: 
                    //column COMMENT value: EOD
                    //column COLOR value: -65536
                    //foreach (DataColumn column in flags.Columns)
                    //{
                    //    Debug.Print("column {0} value: {1}",column.ColumnName,row[column.Ordinal]);
                    //}
                }
                foreach (var f in flags.OrderByDescending(f => f.FlagDate))
                {
                    if (f.FlagType == "BREAK" || f.FlagType == "EOD")
                    {
                        Debug.WriteLine("No TASK Before. Exiting");
                        return;
                    }
                    if (f.FlagType == "TASK")
                    {
                        Debug.WriteLine("TASK Found");
                        Debug.Print("Inserting a new event in GCal from {0} to {1}", f.FlagDate, flag.FlagDate);
                        if (journal == null) journal = new GCalJournal(Username,Password,new Uri(FeedUrl));
                        var start = f.FlagDate;
                        var end = flag.FlagDate;
                        var project = f.Text1;
                        var task = f.Text2;
                        var dt = services.DatabaseServices.ExecuteQuery(string.Format("select sum(duration) as totalduration from activity where snapdate between '{0}' and '{1}'", start.ToString("yyyy-MM-dd HH:mm:ss"), end.ToString("yyyy-MM-dd HH:mm:ss")), "activity");
                        var totalDurationInSec = (long)dt.Rows[0][0];
                        var activeTs = new TimeSpan(totalDurationInSec * 10000000);
                        var totalTs = (end - start);

                        //Insert total time. Should we insert active time instead?
                        journal.InsertNewEntry(start, end, string.Format("{0} - {1}", project, task), string.Format("{0} - {1} (duration: Total={2}h {3}m Active={4}h {5}m)", project, task, totalTs.Hours,totalTs.Minutes, activeTs.Hours, activeTs.Minutes), project);
                        return;
                    }
                }
                Debug.WriteLine("No Task Found before the break");
            }
        }

        public void Configure()
        {
            var frm = new GCalConfigurationForm(services);
            if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //reload config
                LoadConfig();
            }
        }

        public string FriendlyName
        {
            get { return "GCal Plugin"; }
        }

        public string Description
        {
            get { return "Plugin to log tasks to a Google Calendar Journal"; }
        }

        public Guid PluginID
        {
            get { return new Guid("E38D1044-2312-11E0-BF7A-96D0DED72085"); }
        }

        public bool Configurable
        {
            get { return true; }
        }
    }
}
